package io.noties.markwon.plugin.graphviz

import android.graphics.drawable.PictureDrawable
import androidx.annotation.VisibleForTesting
import com.caverock.androidsvg.SVG
import com.github.yeicor.kraphviz.Kraphviz
import io.noties.markwon.base.AbstractMarkwonPlugin
import io.noties.markwon.base.MarkwonConfiguration
import io.noties.markwon.base.MarkwonVisitor
import io.noties.markwon.base.image.AsyncDrawable
import io.noties.markwon.base.image.load.comust.ADVAsyncDrawableLoader
import io.noties.markwon.base.image.span.AsyncDrawableSpan
import io.noties.markwon.base.image.size.CodeBlockImageSizeResolver
import io.noties.markwon.plugin.graphviz.model.GraphvizBlock
import io.noties.markwon.plugin.graphviz.span.GraphvizAsyncDrawableSpan
import io.noties.markwon.plugin.latex.JLatexMathPlugin
import io.noties.markwon.plugin.latex.JLatexMathPlugin.Companion.prepareLatexTextPlaceholder
import io.noties.markwon.plugin.typogram.parser.QuickParser
import io.noties.markwon.plugin.typogram.span.TypogramAsyncDrawableSpan
import org.commonmark.parser.Parser
import timber.log.Timber

class GraphvizPlugin internal constructor(@field:VisibleForTesting val config: Config) :
    AbstractMarkwonPlugin() {

    private val codeBlockImageSizeResolver: CodeBlockImageSizeResolver = CodeBlockImageSizeResolver(true)

    override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
        builder.regeditFencedCodeBlock("graphviz"){
            GraphvizBlock(it.literal)
        }
        builder.regeditFencedCodeBlock("mermaid"){
            GraphvizBlock(it.literal)
        }
    }

    override fun configureParser(builder: Parser.Builder) {
        // @since 4.3.0
        /*if (config.blocksEnabled) {
             builder.customBlockParserFactory(TypogramBlockParser.Factory())
        }*/
        //builder.customDelimiterProcessor(TypogramDelimiterProcessor())
    }

    override fun configureVisitor(builder: MarkwonVisitor.Builder) {
        addBlockVisitor(builder)
        addInlineVisitor(builder)
    }

    private fun addBlockVisitor(builder: MarkwonVisitor.Builder) {
        if (!config.blocksEnabled) {
            return
        }
        builder.on(
            GraphvizBlock::class.java,
            object : MarkwonVisitor.NodeVisitor<GraphvizBlock> {
                override fun visit(visitor: MarkwonVisitor, n: GraphvizBlock) {
                    visitor.blockStart(n)
                    val typogramStr = n.typogram
                    val length = visitor.length()
                    Timber.d("typogram visitor block length:$length")

                    // @since 4.0.2 we cannot append _raw_ latex as a placeholder-text,
                    // because Android will draw formula for each line of text, thus
                    // leading to formula duplicated (drawn on each line of text)
                    visitor.builder().append(JLatexMathPlugin.prepareLatexTextPlaceholder(typogramStr))
                    val configuration = visitor.configuration()
                    val span: AsyncDrawableSpan = TypogramAsyncDrawableSpan(
                        configuration.theme,
                        AsyncDrawable(
                            typogramStr,
                            typogramAsyncDrawableLoader,
                            codeBlockImageSizeResolver,
                            null,
                            true,
                            true
                        ),
                        configuration.theme.colorScheme.codeTextColor.toInt()
                    )
                    visitor.setSpans(length, span)
                    visitor.blockEnd(n)
                }
            })
    }

    private fun addInlineVisitor(builder: MarkwonVisitor.Builder) {
        if (config.blocksEnabled) {
            return
        }
        builder.on(
            GraphvizBlock::class.java,
            object : MarkwonVisitor.NodeVisitor<GraphvizBlock> {
                override fun visit(visitor: MarkwonVisitor, n: GraphvizBlock) {
                    visitor.blockStart(n)
                    val typogramStr = n.typogram
                    val length = visitor.length()

                    // @since 4.0.2 we cannot append _raw_ latex as a placeholder-text,
                    // because Android will draw formula for each line of text, thus
                    // leading to formula duplicated (drawn on each line of text)
                    visitor.builder().append(prepareLatexTextPlaceholder(typogramStr))
                    val configuration = visitor.configuration()
                    val span: AsyncDrawableSpan = GraphvizAsyncDrawableSpan(
                        configuration.theme,
                        AsyncDrawable(
                            typogramStr,
                            typogramAsyncDrawableLoader,
                            codeBlockImageSizeResolver,
                            null,
                            false,
                            true
                        ),
                        configuration.theme.colorScheme.codeTextColor.toInt()
                    )
                    visitor.setSpans(length, span)
                    visitor.blockEnd(n)
                }
            })
    }

    companion object{
        fun create(config: Config = Config()):GraphvizPlugin{
            return GraphvizPlugin(config)
        }
    }
}


class Config() {
    // @since 4.3.0

    val blocksEnabled: Boolean = true
}


val typogramAsyncDrawableLoader = ADVAsyncDrawableLoader{
    val parserGraphviz= Kraphviz()
    val disSvgStr=parserGraphviz.render(it.destination)
    val svg = QuickParser().renderWithSize(disSvgStr)

    Timber.d("graphviz render svg:${svg}")
    val svgRender = SVG.getFromString(svg.first)

    val picture = svgRender.renderToPicture()
    val retDrawable = PictureDrawable(picture)
    retDrawable.setBounds(0,0, svg.second.first.toInt(), svg.second.second.toInt())
    Timber.d("load graphviz picture rect:${retDrawable.bounds}")
    return@ADVAsyncDrawableLoader retDrawable
}